﻿﻿﻿﻿using DeviceCommons.DataHandling;
using DeviceCommons.DeviceMessages.Models;
using System.Buffers;

namespace DeviceCommons.DeviceMessages.Abstractions
{
    public abstract class AbstractMessageSerializer<T> : AbstractMessage<T>, IMessageSerializer<T> where T : IBase
    {
        protected AbstractMessageSerializer(T t) : base(t)
        {
        }

        public Func<string, string>? EncryptFunc { get; set; }
        public Func<byte[], byte[]>? CompressFunc { get; set; }

        public abstract void Serializer(
            ArrayBufferWriter<byte> writer, T message
            );

        public virtual void Serializer(
            ArrayBufferWriter<byte> writer
            ) => Serializer(writer, Model);

        public string Serializer(ArrayBufferWriter<byte> writer, T message, bool isEncrypt = false, bool isCompress = false)
        {
            return Serializer(writer, () => Serializer(writer, message), isEncrypt, isCompress);
        }

        /// <summary>
        /// 序列化消息到十六进制字符串，支持自定义加密密码
        /// </summary>
        /// <param name="writer">缓冲区写入器</param>
        /// <param name="message">消息对象</param>
        /// <param name="isEncrypt">是否加密</param>
        /// <param name="isCompress">是否压缩</param>
        /// <param name="encryptionPassword">加密密码，null时使用默认密码</param>
        /// <returns>十六进制字符串</returns>
        public string Serializer(ArrayBufferWriter<byte> writer, T message, bool isEncrypt, bool isCompress, string? encryptionPassword)
        {
            return Serializer(writer, () => Serializer(writer, message), isEncrypt, isCompress, encryptionPassword);
        }

        public string Serializer(
            ArrayBufferWriter<byte> writer, bool isCompress
            ) => Serializer(writer, () => Serializer(writer), false, isCompress);

        public string Serializer(
            ArrayBufferWriter<byte> writer, T message, bool isCompress
            ) => Serializer(writer, () => Serializer(writer, message), false, isCompress);

        public virtual string Serializer(ArrayBufferWriter<byte> writer, Action action, bool isEncrypt = false, bool isCompress = false)
        {
            return Serializer(writer, action, isEncrypt, isCompress, null);
        }

        /// <summary>
        /// 序列化消息到十六进制字符串，支持自定义加密密码
        /// </summary>
        /// <param name="writer">缓冲区写入器</param>
        /// <param name="action">序列化操作</param>
        /// <param name="isEncrypt">是否加密</param>
        /// <param name="isCompress">是否压缩</param>
        /// <param name="encryptionPassword">加密密码，null时使用默认密码</param>
        /// <returns>十六进制字符串</returns>
        public virtual string Serializer(ArrayBufferWriter<byte> writer, Action action, bool isEncrypt, bool isCompress, string? encryptionPassword)
        {
            string header = isEncrypt ? "enc," : "dec,";
            header += isCompress ? "gzip|" : "raw|";
            action.Invoke();
            ReadOnlySpan<byte> bytes = writer.WrittenSpan;
            ReadOnlySpan<byte> bytesTemp = bytes;
            if (isCompress)
            {
                CompressFunc ??= DeviceMessageUtilities.GZIP.Compress;
                bytesTemp = CompressFunc(bytesTemp.ToArray()).AsSpan();
            }

            string hex = Convert.ToHexString(bytesTemp.ToArray()).ToUpper();
            if (isEncrypt)
            {
                if (EncryptFunc != null)
                {
                    // 使用预设的加密函数
                    hex = EncryptFunc(hex);
                }
                else if (!string.IsNullOrEmpty(encryptionPassword))
                {
                    // 使用提供的密码进行AES加密
                    hex = DeviceMessageUtilities.AES.Value.Encrypt(hex, encryptionPassword);
                }
                else
                {
                    // 使用默认密码
                    hex = DeviceMessageUtilities.AES.Value.Encrypt(hex, DeviceMessageArrayPool.DefaultAedPassword);
                }
            }
            return header + hex;
        }

        public virtual async Task SerializerAsync(
            ArrayBufferWriter<byte> writer, T message, CancellationToken cancellationToken = default
            )
        {
            await SerializerInternalAsync(writer, message, cancellationToken).ConfigureAwait(false);
        }

        public virtual async Task SerializerAsync(
            ArrayBufferWriter<byte> writer, CancellationToken cancellationToken = default
            ) =>
            await SerializerAsync(writer, Model, cancellationToken).ConfigureAwait(false);

        public virtual async Task<string> SerializerAsync(
            ArrayBufferWriter<byte> writer, T message, bool isCompress, CancellationToken cancellationToken = default
            ) =>
            await SerializerAsync(writer, message, false, isCompress, cancellationToken).ConfigureAwait(false);

        public virtual async Task<string> SerializerAsync(
            ArrayBufferWriter<byte> writer, bool isCompress, CancellationToken cancellationToken = default
            ) =>
            await SerializerAsync(writer, false, isCompress, cancellationToken).ConfigureAwait(false);

        public virtual async Task<string> SerializerAsync(
            ArrayBufferWriter<byte> writer, T message, bool isEncrypt, bool isCompress, CancellationToken cancellationToken = default
            )
        {
            return await SerializerAsync(writer, message, isEncrypt, isCompress, null, cancellationToken).ConfigureAwait(false);
        }

        /// <summary>
        /// 异步序列化消息到十六进制字符串，支持自定义加密密码
        /// </summary>
        /// <param name="writer">缓冲区写入器</param>
        /// <param name="message">消息对象</param>
        /// <param name="isEncrypt">是否加密</param>
        /// <param name="isCompress">是否压缩</param>
        /// <param name="encryptionPassword">加密密码，null时使用默认密码</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>十六进制字符串</returns>
        public virtual async Task<string> SerializerAsync(
            ArrayBufferWriter<byte> writer, T message, bool isEncrypt, bool isCompress, string? encryptionPassword, CancellationToken cancellationToken = default
            )
        {
            string header = isEncrypt ? "enc," : "dec,";
            header += isCompress ? "gzip|" : "raw|";

            await SerializerInternalAsync(writer, message, cancellationToken).ConfigureAwait(false);

            ReadOnlyMemory<byte> bytes = writer.WrittenMemory;
            ReadOnlyMemory<byte> bytesTemp = bytes;
            if (isCompress)
            {
                CompressFunc ??= DeviceMessageUtilities.GZIP.Compress;
                bytesTemp = await Task.Run(() => CompressFunc(bytesTemp.ToArray()).AsMemory(), cancellationToken).ConfigureAwait(false);
            }

            string hex = Convert.ToHexString(bytesTemp.ToArray()).ToUpper();
            if (isEncrypt)
            {
                if (EncryptFunc != null)
                {
                    // 使用预设的加密函数
                    hex = await Task.Run(() => EncryptFunc(hex), cancellationToken).ConfigureAwait(false);
                }
                else if (!string.IsNullOrEmpty(encryptionPassword))
                {
                    // 使用提供的密码进行AES加密
                    hex = await Task.Run(() => DeviceMessageUtilities.AES.Value.Encrypt(hex, encryptionPassword), cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    // 使用默认密码
                    hex = await Task.Run(() => DeviceMessageUtilities.AES.Value.Encrypt(hex, DeviceMessageArrayPool.DefaultAedPassword), cancellationToken).ConfigureAwait(false);
                }
            }
            return header + hex;
        }

        public virtual async Task<string> SerializerAsync(
            ArrayBufferWriter<byte> writer, bool isEncrypt, bool isCompress, CancellationToken cancellationToken = default
            ) =>
            await SerializerAsync(writer, Model, isEncrypt, isCompress, cancellationToken).ConfigureAwait(false);

        protected virtual async Task SerializerInternalAsync(
            ArrayBufferWriter<byte> writer, T message, CancellationToken cancellationToken = default
            )
        {
            await Task.Run(() => Serializer(writer, message), cancellationToken).ConfigureAwait(false);
        }

        protected virtual void SerializeWithHeader(ArrayBufferWriter<byte> writer, int headerLength,
            Action<ArrayBufferWriter<byte>> writeHeaderAction, Action<ArrayBufferWriter<byte>> serializeContentAction)
        {
            ArgumentNullException.ThrowIfNull(serializeContentAction);

            serializeContentAction?.Invoke(writer);

            int existingLength = writer.WrittenCount;
            byte[] existingData = existingLength > 0 ? writer.WrittenSpan.ToArray() : [];

            writer.Clear();

            writeHeaderAction?.Invoke(writer);

            if (existingLength > 0)
            {
                writer.Write(existingData);
            }
        }
    }
}
